<template>
	<scroll-view class="com-chat-message" :style="{height:height}" scroll-y :scroll-with-animation="scrollAnimation"
		:scroll-into-view="scrollToView" upper-threshold="50" scroll-anchoring @scrolltoupper="scrolltolower">
		<view>
			<!-- 加载历史数据waitingUI -->
			<com-chat-loading v-if="loadMoreStatus==='loading'"></com-chat-loading>

			<block v-for="(row,index) in items" :key="row.msg.id">
				<!-- 系统消息 -->
				<block v-if="row.type=='system'">
					<view class="message-card" :class="{'self':row.msg.sender==openId}">
						<view class="message-card_system" v-if="row.msg.format==0">
							<text class="message-card_system-text">{{row.msg.content}}</text>
						</view>
					</view>
					<view :id="'siv_'+ row.msg.id"></view>
				</block>
				<!-- 用户消息 -->
				<block v-if="row.type=='user'">
					<view class="message-card" :class="{'self':row.msg.sender===openId}">
						<view class="message-card__avatar" @tap.stop.prevent="avatarClick(row)">
							<u-image width="48rpx" height="48rpx" radius="4rpx"
								:src="(!encryptDisplay&&row.msg.sender==openId?userInfo.head:row.msg.headUrl)||defaultAvatar"></u-image>
						</view>
						<view class="message-card__main">
							<block v-if="showFriendName&&row.msg.sender!==openId">
								<view class="message-card__nickname">{{row.msg.nickname}}</view>
							</block>
							<view class="message-card__message" @longpress="deleteMessage(row)">
								<view v-if="row.loading" class="message-card__main-loading"></view>
								<view v-if="!row.success" class="message-card__main-error"></view>

								<view class="message-card__message-time">{{row.msg.timestamp|chartDatetime(true)}}</view>
								<!-- 文字消息 -->
								<block v-if="row.msg.format==0">
									<rich-text style="word-break: break-word;" :nodes="row.msg.content"
										@tap="textMessageClick(row)"></rich-text>
								</block>
								<!-- 图片消息 -->
								<block v-if="row.msg.format==2">
									<u-image :showMenuByLongpress="false" :showLoading="true" width="160rpx" height="auto"
										:src="row.msg.content" mode="widthFix" @tap.stop.prevent="previewImage(row.msg.content)"
										@load="imageLoad(row)"></u-image>
								</block>
								<!-- 优惠券 -->
								<block v-if="row.msg.format==4">
									<view class="format-coupon" @click="toGoodLists(JSON.parse(row.msg.content))">
										<u-image width="100rpx" height="100rpx"
											:src="JSON.parse(row.msg.content).showInfo.imgUrl"></u-image>
										<view class="format-content">
											{{JSON.parse(row.msg.content).showInfo.fromName}}给你分享了一张优惠券！点击使用！
										</view>
									</view>
								</block>
							</view>
							<view v-if="row.errorMsg" class="message-card__error">{{row.errorMsg}}</view>
						</view>
					</view>
					<view :id="'siv_'+ row.msg.id"></view>
				</block>
			</block>
		</view>
	</scroll-view>
</template>

<script>
	import { defaultAvatar } from '@/config/staticConfig.js'
	import { mapGetters } from 'vuex'
	import commonJS from '@/common/libs/common.js'

	export default {
		props: {
			roomId: {
				type: String,
				default: ''
			},
			// 是否密聊显示
			encryptDisplay: {
				type: Boolean,
				default: false
			},
			// 是否显示朋友名称
			showFriendName: {
				type: Boolean,
				default: false
			},
			height: {
				type: String,
				default: ''
			},
		},
		data() {
			return {
				defaultAvatar,
				scrollAnimation: false,
				scrollToView: null,

				sendTime: '',
				items: [],
				pageNo: 1,
				pageSize: 30,
				loadMoreStatus: 'nomore', //loading / nomore / loadmore
			}
		},
		computed: {
			...mapGetters(['userInfo', 'openId']),
			msgImgList() {
				return this.items.filter(it => it.msg.format === 2).map(it => it.msg.content)
			},
		},
		watch: {
			roomId: {
				handler(nVal, oVal) {
					if (nVal) {
						this.refresherrefresh()
					}
				},
			},
			height: {
				handler(nVal, oVal) {
					setTimeout(() => {
						this.scrollAnimation = false
						this.scrollToAim()
					}, 260)
				},
				immediate: true,
			},
		},
		created() {
			//监听服务器发送信息
			this.$websocket.onChatMessageChange = this.receiveMessage
		},
		beforeDestroy() {
			this.$websocket.onChatMessageChange = () => {}
		},
		methods: {
			// 父组件调用
			pushMessage(data) {
				let fMsg = this.formatMessage(data, 'receive')
				fMsg.loading = true
				this.filterMessage(fMsg)
			},
			async receiveMessage(data) {
				// 发送消息成功，但服务器未响应
				if (data.code == 0) {
					let fMsg = this.formatMessage(data.data, 'receive')
					this.filterMessage(fMsg)
				}
				// 发送消息成功，且服务器响应
				else if (data.code == 1 && data.data.timestamp) {
					let tIndex = this.items.findIndex(
						item => item.msg.tempId && item.msg.tempId.toString() === data.data.timestamp
					)
					if (tIndex > -1) {
						this.items[tIndex].success = true
					}
				}
				// 发送消息失败
				else if (data.code === 2) {
					let fMsg = this.formatMessage(data.data, 'receive')
					fMsg.loading = false
					fMsg.success = false
				}
				// 接收消息成功
				else if (data.code === 3) {
					let fMsg = this.formatMessage(data.data, 'receive')
					this.filterMessage(fMsg)
				}
				// 接收消息失败
				else if (data.code === 4 && data.data) {
					this.addSystemMessage(data.data.message)

					if (data.data.timestamp) {
						let tIndex = this.items.findIndex(
							item => item.msg.tempId && item.msg.tempId.toString() === data.data.timestamp
						)
						if (tIndex > -1) {
							this.items[tIndex].success = false
						}
					}
				}
				// 撤回消息请求提交成功，但服务器未响应
				else if (data.code === 5) {
					let tIndex = this.items.findIndex(item => item.msg.id == data.data.infoId)
					if (tIndex > -1) {
						this.items[tIndex].errorMsg = '撤回中...'
					}
				}
				// 撤回消息请求提交失败
				else if (data.code === 6) {
					let tIndex = this.items.findIndex(item => item.msg.id == data.data.infoId)
					if (tIndex > -1) {
						this.items[tIndex].errorMsg = '撤回失败，请检查网络'
					}
				}
				// 撤回消息请求提交成功，且服务器响应
				else if (data.code === 7) {
					let tIndex = this.items.findIndex(item => item.msg.id == data.data.infoId)
					if (tIndex > -1) {
						this.items.splice(tIndex, 1)
					}
				}
				// 撤回消息请求提交成功，但服务器返回失败
				else if (data.code === 8) {
					let tIndex = this.items.findIndex(item => item.msg.id == data.data.infoId)
					if (tIndex > -1) {
						this.items[tIndex].errorMsg = data.data.message
					}
				}
			},
			// 格式化消息
			formatMessage(message, type = 'api') {
				let result = {}
				switch (type) {
					case 'api':
						result = {
							type: 'user',
							msg: {
								id: message.id,
								action: 0,
								content: message.message,
								sender: message.senderId,
								receiver: message.roomId,
								format: message.type,
								timestamp: message.sendTime,
								nickname: message.senderName,
								headUrl: message.chatHead,
								tempId: message.tempId,
								isRevoke: message.isRevoke,
							},
							loading: false,
							success: true,
							errorMsg: '',
						}
						break;
					case 'receive':
						let { id, action, content, sender, receiver, format, timestamp, extra } = message
						extra = JSON.parse(extra || '{}')
						let { nickname, headUrl, tempId } = extra
						result = {
							type: 'user',
							msg: {
								...{ id, action, content, sender, receiver, nickname, headUrl, tempId },
								format: Number(format),
								timestamp: commonJS.formatTimestamp(timestamp),
								isRevoke: 0,
							},
							loading: false,
							success: true,
						}
						break;
				}
				return result
			},
			// 添加系统消息
			addSystemMessage(text) {
				let tSystem = {
					type: 'system',
					msg: {
						id: Date.now().toString(),
						format: 0,
						content: text
					}
				}
				this.filterMessage(tSystem)
			},
			// 接收消息(筛选处理)
			filterMessage(msg) {
				// 系统消息
				if (msg.type == 'system') {
					this.items.push(msg);
				}
				// 用户消息
				else if (msg.type == 'user') {
					let tIndex = this.items.findIndex(item => item.msg.tempId && item.msg.tempId === msg.msg.tempId)
					if (tIndex > -1) {
						this.items.splice(tIndex, 1, msg);
					} else {
						this.items.push(msg);
					}
				}
				// 滚动到底
				this.scrollAnimation = true
				this.scrollToAim()
			},
			// 滚动到底部
			scrollToAim(id) {
				if (!id && !this.items.length) {
					return
				}
				this.scrollToView = '';
				this.$nextTick(function() {
					let viewid = id ? id : this.items[this.items.length - 1].msg.id
					this.scrollToView = 'siv_' + viewid; //跳转上次的第一行信息位置

					this.$nextTick(() => {
						this.scrollAnimation = false
					})
				});
			},
			// 预览图片
			previewImage(current) {
				uni.previewImage({ // 预览图片  图片路径必须是一个数组
					current: current,
					urls: this.msgImgList
				});
			},
			imageLoad(row) {
				if (row.msg.id === this.items[this.items.length - 1].msg.id) {
					this.$nextTick(() => {
						this.scrollAnimation = true
						this.scrollToAim()
					})
				} else if (this.pageNo === 1 && !this.sendTime) {
					this.scrollToAim()
				}
			},
			//撤回信息（实际是删除，所有人都看不到）
			async deleteMessage(row) {
				console.log(row, '撤回信息');
				if (row.msg.sender !== this.openId) {
					return
				}

				//二次确认 
				uni.showModal({
					title: '提示',
					content: '是否撤回信息',
					success: async (res) => {
						if (res.confirm) {
							let params = {
								infoId: row.msg.id,
							}
							this.$websocket.revokeMessage(params)
						} else if (res.cancel) {}
					}
				});
			},
			toGoodLists(item) {
				console.log(item)
				if (item.jumpInfo.storeId) {
					uni.navigateTo({
						url: '/pagesBusiness/goodsList/goodsList?storeId=' + item.jumpInfo.storeId
					})
				} else {
					uni.navigateTo({
						url: '/pagesBusiness/goodsList/goodsList?goodIds=' + item.jumpInfo.goodIds
					})
				}
			},
			avatarClick(row) {
				// console.log(row);
				this.$emit('avatarClick', row)
			},
			textMessageClick(row) {
				this.$emit('textMessageClick', row)
			},
			// 获取聊天记录
			async getDBData(type = 'refresh') {
				//记住第一个信息ID
				let payload = {
					pageNo: this.pageNo,
					pageSize: this.pageSize,
					openId: this.openId,
					roomId: this.roomId,
					sendTime: this.sendTime,
					type: type === 'refresh' ? 1 : 0, //0-滑动屏幕获取 1-点击未读条数获取
					isDel: 0,
				}
				let res = await this.$api.queryChatHistory(payload)
				if (res.success) {
					let tData = res.result.records
						//过滤 删除和撤回的 item
						.filter(item => item.isDel != 1)
						.map(item => {
							return this.formatMessage(item)
						})
						// 数组反转
						.reverse()

					if (type === 'refresh') {
						this.items = tData
					}
					if (type === 'add') {
						this.items.unshift(...tData)
					}
					this.pageNo = res.result.current
					this.loadMoreStatus = res.result.pages > res.result.current ? 'loadmore' : 'nomore'
				} else {
					this.loadMoreStatus = 'nomore'
				}
				// this.addSystemMessage('欢迎进入聊天室')
			},
			scrolltolower() {
				if (this.loadMoreStatus !== 'loadmore') {
					return
				}
				this.loadMoreStatus = 'loading';
				this.pageNo = 1 // 因为要传入发送时间进行筛选，所以pageNo要重置为1
				this.sendTime = this.items[0].msg.timestamp
				setTimeout(async () => {
					let tPrevLength = this.items.length
					await this.getDBData('add')
					let tNextLength = this.items.length
					let tDiff = tNextLength - tPrevLength - 1
					if (tDiff >= 0) {
						this.scrollToAim(this.items[tDiff > 0 ? tDiff - 1 : tDiff].msg.id)
					}
				}, 500)
			},
			refresherrefresh() {
				this.loadMoreStatus = 'loading'
				this.items = []
				this.pageNo = 1
				setTimeout(async () => {
					await this.getDBData()

					//这段代码很重要，不然每次加载历史数据都会跳到顶部
					this.scrollToAim()
				}, 0)
			},
		}
	}
</script>

<style lang="scss" scoped>
	.com-chat-message {
		width: 100%;
		box-sizing: border-box;
		// background-color: #F7F8FA;
		transition: height .25s;

		.message-card {
			padding: 22rpx 0;

			display: flex;

			.message-card_system {
				width: 100%;
				text-align: center;

				.message-card_system-text {
					padding: 10rpx 20rpx;
					color: #1D2129;
					font-size: 24rpx;
					background-color: #F2F3F5;
					border-radius: 200rpx;
				}
			}

			.message-card__avatar {
				padding: 0 32rpx;
			}

			.message-card__main {
				display: flex;
				flex-direction: column;

				.message-card__nickname {
					height: 32rpx;
					margin-bottom: 10rpx;
					font-size: 22rpx;
					color: #86909C;
					line-height: 32rpx;
				}

				.message-card__message {
					position: relative;
					display: inline-block;
					max-width: 494rpx;
					padding: 20rpx;
					font-size: 32rpx;
					color: #1D2129;
					line-height: 44rpx;
					background-color: #F2F3F5;
					border-radius: 30rpx;

					display: flex;
					flex-direction: column;

					.message-card__message-time {
						margin-bottom: 10rpx;
						font-size: 22rpx;
						color: #86909C;
						line-height: 32rpx;
					}

					$offset: -0.83em;
					$spread: -0.4em;

					.message-card__main-loading,
					.message-card__main-error {
						position: absolute;
						top: 50%;
						left: -60rpx;
						width: 32rpx;
						height: 32rpx;
						transform: translateY(-50%);
					}

					.message-card__main-loading {
						&::before {
							content: "";
							position: absolute;
							width: 100%;
							height: 100%;
							border: 6rpx #ececec solid;
							border-left-color: #c1c1c1;
							border-radius: 100%;
							animation: loading 1.7s infinite ease-out;
						}

						@keyframes loading {
							0% {
								transform: rotate(0deg);
							}

							100% {
								transform: rotate(360deg);
							}
						}
					}

					.message-card__main-error {
						background-color: #ff3d3d;
						border-radius: 100%;

						&::before {
							content: "!";
							position: absolute;
							width: 100%;
							height: 100%;
							color: #fff;
							font-size: 28rpx;

							display: flex;
							justify-content: center;
							align-items: center;
						}
					}
				}
			}

			.message-card__error {
				margin-top: 10rpx;
				padding: 4rpx 16rpx;
				color: #1D2129;
				font-size: 24rpx;
				background-color: #F2F3F5;
				border-radius: 200rpx;
			}
		}

		.message-card.self {
			flex-direction: row-reverse;
			justify-content: flex-start;

			.message-card__main {
				align-items: flex-end;

				.message-card__message {
					color: #fff;
					background-color: #1D2129;
					align-items: flex-end;

					.message-card__message-time {
						color: #fff;
					}
				}
			}
		}

		.format-coupon {
			display: flex;
			align-items: center;

			.format-content {
				margin-left: 20upx;
			}
		}
	}
</style>